using SkiaSharp;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace HamsterDocs.Hosting.Services;

public class ImageService
{
    private readonly ILogger<ImageService> _logger;
    private readonly IConfiguration _configuration;

    public ImageService(ILogger<ImageService> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
    }

    public async Task<ImageProcessResult> SaveAvatarAsync(IFormFile file, Guid userId, string storageRoot, CancellationToken ct = default)
    {
        if (file.Length <= 0) throw new InvalidOperationException("EmptyFile");
        if (!file.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
            throw new InvalidOperationException("InvalidContentType");

        Directory.CreateDirectory(storageRoot);
        var userDir = Path.Combine(storageRoot, "avatars", userId.ToString("N"));
        Directory.CreateDirectory(userDir);

        string ext = GetImageExtension(file.ContentType);
        if (string.IsNullOrEmpty(ext)) ext = ".jpg";

        // 保存与生成路径
        var baseName = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
        var originalFileName = baseName + ext;
        var thumbFileName = baseName + "_thumb.jpg";

        var originalPath = Path.Combine(userDir, originalFileName);
        var thumbPath = Path.Combine(userDir, thumbFileName);

        // 保存原图到磁盘
        using (var inFs = file.OpenReadStream())
        using (var outFs = new FileStream(originalPath, FileMode.Create, FileAccess.Write))
        {
            await inFs.CopyToAsync(outFs, ct);
        }

        // 使用 SkiaSharp 生成缩略图（最长边 256、JPEG 质量 85、透明填充白色、应用常见 EXIF 方向）
        int width;
        int height;

        // 原图文件大小（用于跳过小图缩略图）
        var fileSizeBytes = new FileInfo(originalPath).Length;

        bool shouldSkipThumb;

        using (var fs = File.OpenRead(originalPath))
        {
            // 先尝试用 SKCodec 获取 EXIF 方向等元信息
            using var codec = SKCodec.Create(fs);
            if (codec == null)
            {
                // 退化到直接解码获取尺寸
                fs.Position = 0;
                using var fallbackBitmap = SKBitmap.Decode(fs);
                if (fallbackBitmap == null)
                    throw new InvalidOperationException("ImageDecodeFailed");

                width = fallbackBitmap.Width;
                height = fallbackBitmap.Height;

                // 判断是否跳过缩略图：min(width,height) ≤ 256 或 文件大小 ≤ 100KB
                shouldSkipThumb = Math.Min(width, height) <= 256 || fileSizeBytes <= 100 * 1024;

                if (!shouldSkipThumb)
                {
                    // 计算目标尺寸（最长边 256），采用 Cubic 采样提升文本可读性
                    const int thumbSize = 256;
                    float scale = Math.Min(1f, Math.Min((float)thumbSize / width, (float)thumbSize / height));
                    int dstW = Math.Max(1, (int)Math.Round(width * scale));
                    int dstH = Math.Max(1, (int)Math.Round(height * scale));

                    var info = new SKImageInfo(dstW, dstH, SKColorType.Rgba8888, SKAlphaType.Premul);
                    using var surface = SKSurface.Create(info);
                    var canvas = surface.Canvas;

                    // 透明背景填充为白色
                    canvas.Clear(SKColors.White);

                    // 按比例绘制，使用 Cubic 重采样以提高文字边缘清晰度
                    var srcRect = new SKRect(0, 0, fallbackBitmap.Width, fallbackBitmap.Height);
                    var dstRect = new SKRect(0, 0, dstW, dstH);
                    using var imageToDraw = SKImage.FromBitmap(fallbackBitmap);
                    var cubic = new SKSamplingOptions(new SKCubicResampler(1f / 3f, 1f / 3f));
                    canvas.DrawImage(imageToDraw, srcRect, dstRect, cubic);
                    canvas.Flush();

                    using var snapshot = surface.Snapshot();
                    using var data = snapshot.Encode(SKEncodedImageFormat.Jpeg, 85);
                    using var outThumb = new FileStream(thumbPath, FileMode.Create, FileAccess.Write);
                    data.SaveTo(outThumb);
                }
            }
            else
            {
                // 根据 EXIF 方向绘制为“纠正方向”的图像
                var origin = codec.EncodedOrigin;

                // 解码原始位图的基础信息
                var info = codec.Info;
                width = info.Width;
                height = info.Height;

                // 判断是否跳过缩略图：min(width,height) ≤ 256 或 文件大小 ≤ 100KB
                shouldSkipThumb = Math.Min(width, height) <= 256 || fileSizeBytes <= 100 * 1024;

                if (!shouldSkipThumb)
                {
                    // 计算纠正后的尺寸（旋转 90/270 交换宽高）
                    bool rotate90 = origin == SKEncodedOrigin.RightTop || origin == SKEncodedOrigin.LeftBottom;
                    bool rotate180 = origin == SKEncodedOrigin.BottomRight;
                    bool rotate270 = origin == SKEncodedOrigin.LeftTop || origin == SKEncodedOrigin.RightBottom;

                    int orientedW = (rotate90 || rotate270) ? height : width;
                    int orientedH = (rotate90 || rotate270) ? width : height;

                    // 解码像素到位图
                    // 注意：SKCodec 解码并不会自动应用 EncodedOrigin，所以我们使用画布应用变换
                    fs.Position = 0;
                    using var srcBitmap = SKBitmap.Decode(fs);
                    if (srcBitmap == null)
                        throw new InvalidOperationException("ImageDecodeFailed");

                    // 先将原图按 EXIF 方向纠正到一张“正向”的 SKImage
                    var orientedInfo = new SKImageInfo(orientedW, orientedH, SKColorType.Rgba8888, SKAlphaType.Premul);
                    using var orientedSurface = SKSurface.Create(orientedInfo);
                    var orientedCanvas = orientedSurface.Canvas;
                    orientedCanvas.Clear(SKColors.White); // 透明转白底

                    using var srcImage = SKImage.FromBitmap(srcBitmap);

                    // 设置变换矩阵以应用旋转
                    if (rotate90)
                    {
                        orientedCanvas.Translate(orientedW, 0);
                        orientedCanvas.RotateDegrees(90);
                    }
                    else if (rotate180)
                    {
                        orientedCanvas.Translate(orientedW, orientedH);
                        orientedCanvas.RotateDegrees(180);
                    }
                    else if (rotate270)
                    {
                        orientedCanvas.Translate(0, orientedH);
                        orientedCanvas.RotateDegrees(270);
                    }

                    var drawRect = new SKRect(0, 0, width, height);
                    var cubic1 = new SKSamplingOptions(new SKCubicResampler(1f / 3f, 1f / 3f));
                    orientedCanvas.DrawImage(srcImage, drawRect, cubic1);
                    orientedCanvas.Flush();

                    using var orientedImage = orientedSurface.Snapshot();

                    // 计算目标尺寸（最长边 256）
                    const int thumbSize = 256;
                    float scale = Math.Min(1f, Math.Min((float)thumbSize / orientedW, (float)thumbSize / orientedH));
                    int dstW = Math.Max(1, (int)Math.Round(orientedW * scale));
                    int dstH = Math.Max(1, (int)Math.Round(orientedH * scale));

                    var dstInfo = new SKImageInfo(dstW, dstH, SKColorType.Rgba8888, SKAlphaType.Premul);
                    using var dstSurface = SKSurface.Create(dstInfo);
                    var dstCanvas = dstSurface.Canvas;
                    dstCanvas.Clear(SKColors.White);

                    var srcRect2 = new SKRect(0, 0, orientedW, orientedH);
                    var dstRect2 = new SKRect(0, 0, dstW, dstH);
                    var cubic2 = new SKSamplingOptions(new SKCubicResampler(1f / 3f, 1f / 3f));
                    dstCanvas.DrawImage(orientedImage, srcRect2, dstRect2, cubic2);
                    dstCanvas.Flush();

                    using var finalImage = dstSurface.Snapshot();
                    using var data = finalImage.Encode(SKEncodedImageFormat.Jpeg, 85);
                    using var outThumb = new FileStream(thumbPath, FileMode.Create, FileAccess.Write);
                    data.SaveTo(outThumb);

                    // 覆盖返回尺寸为纠正前的源尺寸（与现有逻辑一致返回源图宽高）
                    // 如果希望返回纠正后的宽高，可改为 width=orientedW,height=orientedH
                    // 当前保持原行为：width/height 使用原始读取的值（未旋转交换）
                }
            }
        }

        string fileHash;
        using (var readOriginal = File.OpenRead(originalPath))
        {
            using var sha = System.Security.Cryptography.SHA256.Create();
            var hash = await sha.ComputeHashAsync(readOriginal, ct);
            fileHash = Convert.ToHexString(hash);
        }

        var webOriginal = ToWebPath(originalPath, storageRoot);
        var webThumb = (Math.Min(width, height) <= 256 || fileSizeBytes <= 100 * 1024)
            ? webOriginal
            : ToWebPath(thumbPath, storageRoot);

        return new ImageProcessResult(
            webOriginal,
            webThumb,
            file.ContentType,
            width,
            height,
            fileHash
        );
    }

    private static string GetImageExtension(string contentType)
    {
        return contentType.ToLowerInvariant() switch
        {
            "image/png" => ".png",
            "image/jpeg" => ".jpg",
            "image/jpg" => ".jpg",
            "image/webp" => ".webp",
            "image/gif" => ".gif",
            _ => ".jpg"
        };
    }

    private static string ToWebPath(string absolutePath, string storageRoot)
    {
        var fullRoot = Path.GetFullPath(storageRoot);
        var fullFile = Path.GetFullPath(absolutePath);
        var relative = Path.GetRelativePath(fullRoot, fullFile).Replace('\\', '/');
        return "/static/" + relative;
    }

    public record ImageProcessResult(
        string OriginalWebPath,
        string ThumbWebPath,
        string ContentType,
        int Width,
        int Height,
        string FileHash
    );
}